package cz.muni.fi.pb138.xml.wrda.servise;

import cz.muni.fi.pb138.xml.wrda.core.WAR;
import cz.muni.fi.pb138.xml.wrda.dao.WARDao;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.Namespace;
import org.jdom2.filter.Filters;
import org.jdom2.input.SAXBuilder;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * @author Michal Krajcovic <422783@mail.muni.cz>
 * @version 5/8/14
 */
public class WARServiceImpl implements WARService {

    public static final String REPO_WAR = "repo/war/";
    @Autowired
    WARDao warDao;

    @Override
    public void save(WAR war) throws IllegalArgumentException {
        warDao.save(war);
    }

    @Override
    public void delete(WAR war) throws IllegalArgumentException {
        File f = new File(REPO_WAR + war.getFileName() + "/" + war.getTimeStamp() + ".war");
        if (f.exists()) {
            String d = f.getParent();
            f.delete();
            File dir = new File(d);
            if (dir.list().length == 0) {
                dir.delete();
            }
        }
        warDao.delete(war);
    }

    @Override
    public List<WAR> getAllEntries() {
        return warDao.getAllEntries();
    }

    @Override
    public File createFile(String fileName, Long timeStamp) throws IllegalArgumentException {

        String warFolder = fileName.substring(0, fileName.length() - 4);
        Path p = Paths.get(REPO_WAR + warFolder);

        if (!Files.exists(p)) {
            try {
                Files.createDirectory(p);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        File file = new File(REPO_WAR + warFolder + "/" + timeStamp + ".war");
        try {
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return file;
    }

    @Override
    public void saveDbEntry(File f, Long timeStamp) throws IllegalArgumentException {
        Document document = extractWebXml(f);
        if (document != null) {
            //implicit namespace of web-app
            Namespace ns = Namespace.getNamespace("ns", "http://java.sun.com/xml/ns/javaee");
            XPathExpression<Element> xpathFilters = XPathFactory.instance().compile("/ns:web-app/ns:filter", Filters.element(), null, ns);
            XPathExpression<Element> xpathListeners = XPathFactory.instance().compile("/ns:web-app/ns:listener", Filters.element(), null, ns);

            List<Element> filterElements = xpathFilters.evaluate(document);
            List<String> filters = new ArrayList<>();
            for (Element filter : filterElements) {
                List<Element> filterClasses = filter.getChildren("filter-class", ns);
                for (Element filterClass : filterClasses) {
                    filters.add(filterClass.getValue());
                }
            }

            List<Element> listenerElements = xpathListeners.evaluate(document);
            List<String> listeners = new ArrayList<>();
            for (Element listener : listenerElements) {
                List<Element> listenerClasses = listener.getChildren("listener-class", ns);
                for (Element listenerClass : listenerClasses) {
                    listeners.add(listenerClass.getValue());
                }
            }

            WAR war = new WAR();
            war.setTimeStamp(timeStamp);
            war.setFilters(filters);
            war.setListeners(listeners);
            war.setFileName(f.getParentFile().getName());
            war.setDocument(document);

            warDao.save(war);
        }
    }

    @Override
    public List<String> getFileNames() {
        return warDao.getFileNames();
    }

    @Override
    public List<WAR> getByFilter(String filterName) {
        return warDao.getByFilter(filterName);
    }

    @Override
    public List<WAR> getByFileName(String fileName) throws IllegalArgumentException {
        return warDao.getByFileName(fileName);
    }

    @Override
    public List<WAR> getByListener(String listenerName) {
        return warDao.getByListener(listenerName);
    }

    @Override
    public WAR getByFileNameAndTimeStamp(String fileName, Long timeStamp) {
        return warDao.getByFileNameAndTimeStamp(fileName, timeStamp);
    }

    private Document extractWebXml(File f) {
        ZipFile zf = null;
        try {
            zf = new ZipFile(f);
        } catch (IOException e) {
            e.printStackTrace();
        }

        ZipEntry xmlEntry = zf.getEntry("WEB-INF/web.xml");
        if (xmlEntry != null) {
            InputStream zipStream = null;
            try {
                zipStream = zf.getInputStream(xmlEntry);
            } catch (IOException e) {
                e.printStackTrace();
            }
            SAXBuilder builder = new SAXBuilder();

            Document document = null;
            try {
                document = (Document) builder.build(zipStream);
            } catch (JDOMException | IOException e) {
                e.printStackTrace();
            }
            return document;
        }
        return null;
    }
}
